#ifndef __M_ROUTING_H__
#define __M_ROUTING_H__

#include "exchange.hpp"
#include "queue.hpp"
#include "binding.hpp"
#include "message.hpp"

namespace mmq
{

    class Routing
    {
    public:
        static bool IsLegalRoutingKey(const std::string &routing_key)
        {
            // 判断是否包含非法字符即可，合法字符(a~z A~Z 0~9 . _)
            for(auto &ch : routing_key)
            {
                if((ch >= 'a' && ch <= 'z') ||
                   (ch >= 'A' && ch <= 'Z') ||
                   (ch >= '0' && ch <= '9') ||
                   (ch == '.' || ch == '_'))
                {
                    continue;
                }
                return false;
            }
            return true;
        }

        static bool IsLegalBindingKey(const std::string &binding_key)
        {
            // 1. 判断是否包含非法字符，合法字符(a~z A~Z 0~9 . _ * #)
            for(auto &ch : binding_key)
            {
                if((ch >= 'a' && ch <= 'z') ||
                   (ch >= 'A' && ch <= 'Z') ||
                   (ch >= '0' && ch <= '9') ||
                   (ch == '.' || ch == '_') ||
                   (ch == '*' || ch == '#'))
                {
                    continue;
                }
                return false;
            }
            // 2. * 和 # 必须独立存在，如news.music.*.#
            std::vector<std::string> sub_words;
            StrHelper::Split(binding_key, ".", sub_words);
            for(auto &word : sub_words)
            {
                if(word.size() > 1 && 
                (word.find('*') != std::string::npos || 
                word.find('#') != std::string::npos))
                {
                    return false;
                }
            }
            // 3. *和#不能连续出现
            for(int i = 1; i < sub_words.size(); i++)
            {
                if(sub_words[i] == "#" && sub_words[i-1] == "*") return false;
                if(sub_words[i] == "#" && sub_words[i-1] == "#") return false;
                if(sub_words[i] == "*" && sub_words[i-1] == "#") return false;
            }
            return true;
        }

        static bool Route(ExchangeType type, const std::string &routing_key, const std::string &binding_key)
        {
            if(type == ExchangeType::DIRECT)
            {
                return routing_key == binding_key;
            }
            else if(type == ExchangeType::FANOUT)
            {
                return true;
            }
            // 主题交换，进行模式匹配 news.#  news.music.pop
            // 1. 将binding_key和routing_key进行字符串分割，得到各个单词数组
            std::vector<std::string> bkeys, rkeys;
            int n = StrHelper::Split(binding_key, ".", bkeys);
            int m = StrHelper::Split(routing_key, ".", rkeys);
            // 2. 定义标记数组，并初始化[0][0]位置，其他位置为false
            std::vector<std::vector<bool>> dp(n + 1, std::vector<bool>(m + 1, false));
            dp[0][0] = true;
            // 3. 如果binding_key以"#"起始，则将"#"对应行的第0列置为true
            for(int i = 1; i <= n; i++)
            {
                if(bkeys[i-1] == "#")
                {
                    dp[i][0] = true;
                    continue;
                }
                break;
            }
            // 4. 使用rkeys中的每个单词与bkeys中的每个单词进行匹配并标记数组
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= m; j++)
                {
                    if(bkeys[i-1] == "#")
                    {
                        // 如果当前bkeys为"#"，需要从左上，左，上方继承结果
                        dp[i][j] = dp[i-1][j-1] | dp[i][j-1] | dp[i-1][j];
                    }
                    else if(bkeys[i-1] == "*" || bkeys[i-1] == rkeys[j-1])
                    {
                        // 如果当前bkeys为"*"或者两个单词相等，则匹配成功，从左上方继承结果
                        dp[i][j] = dp[i-1][j-1];
                    }
                    else dp[i][j] = false;
                }
            }
            return dp[n][m];
        }
    };

}

#endif